package com.card.game.pdk;

import java.util.Vector;

import com.card.game.Card;

public class Hand
{
	//花色 (-1=解析的时候出现错误,0=黑桃,1=红桃,2=梅花,3=方片,4=王)
	//序号 (小王的序号0,大王的序号是1,其他标准的牌:2--13对应牌面的牌,14对应"A"牌(因为"A"牌比K牌还大),15对应2, -1:获取错误)
    public Vector<Card> cards;//牌列表向量
    //一般牌型:
    public static final int SINGLE = 0; //单牌:单个牌。例如: '8'或者'4'
    public static final int PAIR = 1; //对牌:两个点数相同的牌。 例如"55"或者'88'
    public static final int THREE = 2; //三张牌:三张点数相同的牌。例如"555"或者'888'
    public static final int THREESINGLE = 3; //三带一:三张同点牌 ＋ 一张单牌。例如:三张３＋单４,例如'3334'
    public static final int THREEPAIR = 4; //三带二:三张同点牌 ＋ 一对牌。例如:三张３＋对４,例如'33344'
    public static final int LINK = 5; //单顺:五张或更多连续的单牌。例如:单３＋单４＋单５＋单６＋单７。不包括２点和双王。,例如'345678910JQKA'
    public static final int LINKPAIR = 6; //双顺:三对或更多连续的对牌。例如:对３＋对４＋对５。不包括２点和双王。例如''334455667788991010JJQQKKAA'
    public static final int LINKTHREE = 7; //三顺:二个或更多连续的三张牌。例如:三张３＋三张４＋三张５。不包括２点和双王。也叫飞机不带翅膀。例如'333444555'
    public static final int LINKTHREE_CB = 8; //飞机带翅膀。三顺＋同数量的单牌（或同数量的对牌）。例如:三张３＋三张４＋对５＋对６ 或 三张３＋三张４＋三张５＋单６＋单７＋单８
    public static final int FOUR_TWOSINGLE = 9; //四带二单牌:四张牌＋任意两张单牌例如:四张５＋单３＋单８
    public static final int FOUR_TWOPAIR = 10; //四带二对牌:四张牌＋任意两对牌 例如四张４＋对５＋对７

    //特别牌型:
    public static final int NONE = -1; //-----是不符合游戏规则的牌列表
    public static final int PASS = 100; //pass
    public static final int BOMB = 200; //炸弹:四张同点牌。如四个3。除火箭和比自己大的炸弹外,什么牌型都可打。
//    public static final int HUOJIAN = 400; //火箭:即双王（双王牌）,什么牌型都可打,是最大的牌。
    public static final int RUAN_BOMB = 150; //软炸弹--癞子炸弹
    
    public int value;//标识值
    public Card bigcard;//最大的牌对象
    public Card smallCard = null;  //一手牌中最小的牌

    /**
     * 构造函数
     * @param vector 牌列表
     * @param isStringName 是否列表中的牌时字符串形式存放的
     */
    public Hand(Vector<Card> vector,boolean isStringName)
    {
    	this.cards = vector;
        analyze();//进行分析!!!!!!!!!!!!!!
    }

    /**
     * 取出列表中牌的个数
     * @return
     */
    public int size()
    {
        return cards.size();
    }

    /**
     * 是规则牌吗
     * @return
     */
    public boolean isRegular()
    {
        return value >= 0;  //备注:0代表单,也是允许的
    }

    /**
     * 检查是否是"火箭"
     * @return
     */
    /*public boolean isHhuoJian()
    {
        if (cards.size()!=2) return false;//如果不是2张牌则认为不是火箭
        return cards.get(0).isJoker() && cards.get(1).isJoker();//要求两张牌斗是王
    }*/

    /**
     * 检查是否是"对"
     * @param vector 牌列表
     * @param i 从第几个元素开始比较
     * @return
     */
    public boolean isPair(Vector<Card> vector, int i)
    {
        if(vector==null || vector.size() < i + 2) return false; //范围检查,防止越界

        Card card = vector.get(0 + i);
        Card card1 = vector.get(1 + i);

        return card.getIndex() == card1.getIndex(); //比较从指定位置开始两张牌的序号是否一样
    }

    /**
     * 检查是否是三张牌:三张点数相同的牌。例如"555"或者'888'
     * @param vector 牌列表
     * @param i 从第几个元素开始比较
     * @return
     */
    public boolean isThree(Vector<Card> vector, int i)
    {
        if(vector==null || vector.size() < i + 3) return false;//范围检查,防止越界

        Card card = vector.get(0 + i);
        Card card1 = vector.get(1 + i);
        Card card2 = vector.get(2 + i);
        if(card.getIndex() == card1.getIndex() && card.getIndex() == card2.getIndex()) //比较序号是否一样
        {
            bigcard = card2; //如果一样,则设置bigcard,因为根据游戏规则,如果有3同张,则比较3同张的大小
            return true;
        } else
        {
            return false;
        }
    }

    /**
     * 检查是否是三带一:三张同点牌 ＋ 一张单牌。例如:三张３＋单４,例如'3334'
     * @param vector
     * @return
     */
    boolean isThreeSingle()
    {
        if(cards == null || cards.size() != 4) return false;//范围检查
        return isThree(cards, 0) || isThree(cards, 1);
    }

    /**
      检查是否是连,五张或更多连续的单牌。例如:单３＋单４＋单５＋单６＋单７。不包括２点和双王。,例如'345678910JQKA'
    */
     boolean isLink()
     {
         if(cards == null || cards.size() < 5) return false;//范围检查,保证联的个数不小于最少允许的牌的个数,重要!

         for(int i = 0; i < cards.size() - 1; i++)
         {
             Card card = cards.get(i);
             Card card1 = cards.get(i + 1);

             if (card.getIndex()==15 || card1.getIndex()==15) return false;//不允许包含2
             if (card.isJoker() || card1.isJoker()) return false;//不允许包含王

             if(card1.getIndex() != card.getIndex() + 1)
                 return false;
         }

         bigcard =  cards.lastElement(); //如果是联则更新bigcard
         smallCard =  cards.firstElement();
         return true;
     }


     /**
      * 检查是否是三带二:三张同点牌 ＋ 一对牌。例如:三张３＋对４,例如'33344'
      * @param vector
      * @return
      */
     public boolean isThreePair()
     {
         if(cards == null || cards.size() != 5) return false;//范围检查

         if(isPair(cards, 0) && isThree(cards, 2)) return true;
         if(isThree(cards, 0) && isPair(cards, 3)) return true;
         return false;
     }

     /**
      * 检查是否是双顺:三对或更多连续的对牌。例如:对３＋对４＋对５。不包括２点和双王。例如''334455667788991010JJQQKKAA'
      * @param vector
      * @return
      */
     boolean isLinkPair()
     {
         if(cards == null || cards.size() < 6 || cards.size() % 2 != 0) return false;//要求必须是偶数张牌!并且不小于6张牌(备注:可以是6张)

         for(int i = 0; i < cards.size(); i += 2)
             if(!isPair(cards, i))
                 return false;  //依次检查是否是对

         //是否是简单连（注意是要间隔一个比较）
         for(int i1 = 0; i1 < cards.size() - 2; i1 += 2)
         {
             Card card = cards.get(i1);
             Card card1 = cards.get(i1 + 2);

             if (card.getIndex()==15 || card1.getIndex()==15) return false;//不允许包含2
             if (card.isJoker() || card1.isJoker()) return false;//不允许包含王

             if(card1.getIndex() != card.getIndex() + 1)
                 return false;
         }

         bigcard =  cards.lastElement(); //如果是联则更新bigcard
         smallCard =  cards.firstElement();
         return true;
     }

     /**
      * 检查是否是三顺:二个或更多连续的三张牌。例如:三张３＋三张４＋三张５。不包括２点和双王。也叫飞机不带翅膀。例如'333444555'
      * @param vector
      * @return
      */
     boolean isLinkThree(Vector<Card> aVec)
     {
         if(aVec == null || aVec.size() < 6 || aVec.size() % 3 != 0) return false;//范围检查,要求必须是3的倍数张牌!并且不小于6张牌(备注:可以是6张)

         for(int i = 0; i < aVec.size(); i += 3)
             if(!isThree(aVec, i))
                 return false;  //依次检查是否是3同张

         //是否是简单连（注意是要间隔2个比较）
         for(int i1 = 0; i1 < aVec.size() - 3; i1 += 3)
         {
             Card card = aVec.get(i1);
             Card card1 = aVec.get(i1 + 3);

             if (card.getIndex()==15 || card1.getIndex()==15) return false;//不允许包含2
             if (card.isJoker() || card1.isJoker()) return false;//不允许包含王

             if(card1.getIndex() != card.getIndex() + 1)
                 return false;
         }

         bigcard =  aVec.lastElement(); //如果是联则更新bigcard
         smallCard =  aVec.firstElement();
         return true;
     }
     /**
      * 检查是否是炸弹,四张牌点相同的牌,如:4444
      * @param vector 牌列表
      * @param i 从第几个元素开始比较
      * @return
      */
       public boolean isFour(Vector<Card> vector, int i)
     {
         if(vector==null || vector.size() < i + 4) return false;//范围检查,防止越界

         Card card = vector.get(0 + i);
         Card card1 = vector.get(1 + i);
         Card card2 = vector.get(2 + i);
         Card card3 = vector.get(3 + i);
         if(card.getIndex() == card1.getIndex() && card.getIndex() == card2.getIndex() && card.getIndex() == card3.getIndex()) //比较序号
         {
             bigcard = card3;  //注意:如果序号一样,则更新最大牌对象（游戏规则）
             return true;
         } else
         {
             return false;
         }
     }

     /**
      * 检查是否是四带二单牌:四张牌＋任意两张单牌例如:四张５＋单３＋单８
      * @return
      */
     boolean isFourTwoSingle()
     {
         if(cards == null || cards.size() != 6) return false;//范围检查

         return isFour(cards, 0 ) || isFour(cards, 1) || isFour(cards, 2);
     }

     /**
      * 检查是否是四带二对牌:四张牌＋任意两对牌 例如四张４＋对５＋对７
      * @return
      */
     boolean isFourTwoPair()
     {
         if(cards == null || cards.size() != 8) return false;//范围检查

         if (isPair(cards, 0) && isPair(cards, 2) && isFour(cards, 4)) return true;
         if (isPair(cards, 0) && isPair(cards, 6) && isFour(cards, 2)) return true;
         if (isPair(cards, 4) && isPair(cards, 6) && isFour(cards, 0)) return true;
         return false;
     }

     /**
      * 检查是否是飞机带翅膀。三顺＋同数量的单牌（或同数量的对牌）。例如:三张３＋三张４＋对５＋对６ 或 三张３＋三张４＋三张５＋单６＋单７＋单８
      * @return
      */
     boolean isLinkThree_CB()
     {
         //把cards复制一份到clonedCards,仅仅对复制品进行操作
         Vector<Card> clonedCards=new Vector<>();
         for (int i=0;i<cards.size();i++)
         {
             clonedCards.add(cards.get(i));
         }

         //从复制品中挑出3同张到aVec中
         Vector<Card> aVec=new Vector<>();
         for (int i=0;i<clonedCards.size()-2;i++)
         {
             if (this.isThree(clonedCards,i))
             {
                 aVec.add(clonedCards.get(i));
                 aVec.add(clonedCards.get(i+1));
                 aVec.add(clonedCards.get(i+2));
                 i+=2;
             }
         }

         //把clonedCards中的3同张删除(删除后clonedCards中仅仅剩下单牌或者对牌)
         for (int i=0;i<aVec.size();i++)
         {
             clonedCards.removeElement(aVec.get(i));
         }

         //检查aVec是三顺,如果不是三顺则直接返回false
         if (!isLinkThree(aVec)) {
        	 boolean isCan = false;
        	 //是一个大飞机 比如 666777888 444  或者 是666777888999 4445 飞机膀子是三张的情况 add by syl 2014-02-08
        	 if(aVec.size() >= 4) {
        		 //先移除前三张
        		 Vector<Card> cv = new Vector<>();
        		 Vector<Card> aVecClone = (Vector<Card>)aVec.clone();
        		 for (int i = 0; i < 3; i++) {
        			 cv.add(aVecClone.remove(0));
        		 }
        		 if(isLinkThree(aVecClone)) {
        			 aVec.removeAll(cv);
        			 clonedCards.addAll(cv);
        			 isCan = true;
        		 }
        		 
        		 //移除最后三张
        		 if(!isCan) {
        			 cv.clear();
        			 aVecClone = (Vector)aVec.clone();
        			 for (int i = 0; i < 3; i++) {
            			 cv.add(aVecClone.remove(aVecClone.size()-1));
            		 }
        			 if(isLinkThree(aVecClone)) {
            			 aVec.removeAll(cv);
            			 clonedCards.addAll(cv);
            			 isCan = true;
            		 }
        		 }
        		 
        	 }
        	 if(!isCan) {
        		 return false;
        	 }
         }

         //现在aVec中是三顺,计算出三顺的个数
         int iCount=aVec.size()/3;

         //检查clonedCards中剩余的牌是否是iCount对
         if(clonedCards.size() ==2*iCount)
         {
             for (int i = 0; i < clonedCards.size(); i += 2)
                 if (!isPair(clonedCards, i))
                     return false;
             return true;
         }

         //如果不是iCount对,则检查是否是iCount个单牌
         if (clonedCards.size() ==iCount) {
        	 return true;
         }else{
        	 //是一个大飞机 是5556667778889994 飞机膀子是三张的情况 add by syl 2014-02-08
        	 if(isLinkThree(aVec) && iCount == 5 && clonedCards.size() == 1) {
        		 return true;
        	 }
        	 if(isLinkThree(aVec) && iCount == 6 && clonedCards.size() == 2) {
        		 return true;
        	 }
         }

         //以上都不满足,则返回false
         return false;
     }

    /**-------------------------------------------------------------------------
     * 分析
     -------------------------------------------------------------------------*/
    public void analyze()
    {
        //对牌进行排序,确保按牌的大小顺序排列
        sortCards(cards);

        int i = cards.size();//牌的个数
        bigcard = size() <= 0 ? null : cards.lastElement(); //如果本牌列表中牌的个数小于等于0,则最大牌对象为null,否则为牌列表中最后面的牌
        value = -1;//初始化牌的数值为-1(也就是不符合规则的标志值)

        //如果牌的个数为0则表示是PASS
        if (i==0)
        {
            value = PASS;
            return;
        }

        //如果是一张则设置成单张的标志
        if (i==1)
        {
            value = SINGLE;
            return;
        }

        //如果是2张
        if (i==2)
        {
            //先判断是否是火箭,如果是则设置火箭的标志
           /* if (isHhuoJian())
            {
                value = HUOJIAN;
                return;
            }*/
            //如果不是火箭则再判断是否是对,如果是对则设置对的标志
            if (isPair(cards, 0))
                value = PAIR;
            return;
        }

        //如果是3张牌
        if (i==3)
        {
            if(isThree(cards, 0)) value = THREE;//比较是否是三张牌:三张点数相同的牌。例如"555"或者'888'
            return;
        }

        //如果是4张牌
        if (i==4)
        {
            if(isFour(cards, 0))
            {
//            	if(LzCardManager.containLzCard(cards) > 0) {
//            		value = RUAN_BOMB;
//            	}else{
//            	}
            	value = BOMB; //如果是炸弹,则设置是炸弹的标志
                return;
            }
            //当不是炸弹的时候再检查是否是3带1
            if (isThreeSingle())
                value = THREESINGLE; //比较是否是三带一:三张同点牌 ＋ 一张单牌。例如:三张３＋单４,例如'3334'
            return;
        }

        //如果是5张牌
        if (i==5)
        {
            //检查是否是连
            if(isLink())
            {
                value = LINK;
                return;
            }
            //如果不是连,则检查是否是三带二
            if (isThreePair())
                value = THREEPAIR;
            return;
        }

        //程序执行到这里的时候牌的张数大于等于6张牌==================================
        //检查是否是连
        if (isLink())
        {
            value = LINK;
            return;
        }
        //检查是否是双顺:三对或更多连续的对牌。例如:对３＋对４＋对５。不包括２点和双王。例如''334455667788991010JJQQKKAA'
        if (isLinkPair())
        {
            value = LINKPAIR;
            return;
        }
        //检查是否是三顺:二个或更多连续的三张牌。例如:三张３＋三张４＋三张５。不包括２点和双王。也叫飞机不带翅膀。例如'333444555'
        if (isLinkThree(cards))
        {
            value = LINKTHREE;
            return;
        }
        //检查是否是四带二单牌:四张牌＋任意两张单牌例如:四张５＋单３＋单８
        if (isFourTwoSingle())
        {
            value = FOUR_TWOSINGLE;
            return;
        }
        //检查是否是四带二对牌:四张牌＋任意两对牌 例如四张４＋对５＋对７
        if (isFourTwoPair())
        {
            value = FOUR_TWOPAIR;
            return;
        }

        //检查是否是飞机带翅膀。三顺＋同数量的单牌（或同数量的对牌）。例如:三张３＋三张４＋对５＋对６ 或 三张３＋三张４＋三张５＋单６＋单７＋单８
        if (isLinkThree_CB())
        {
            value = LINKTHREE_CB;
            return;
        }

    }

    /**
     * 比较大小
     * @param hand
     * @return 如果本牌比目标牌大,则返回值大于0,否则返回值小于等于0(注意:小于0和等于0的含义是一样的,使用的时候没有什么区别!)
     * 备注:调用本函数的时候,应该调用是后出牌的hand的本函数,参数hand表示比本hand先出的牌
     */
    public int compareTo(Hand hand)
    {
        //检查合法性
        if(hand == null || hand.value < 0 || value < 0) return 0;

        //如果本牌列表不是规则的,或者参数牌列表不是规则的,则直接返回0
        if(!isRegular() || !hand.isRegular()) return 0;

        //如果本牌列表的分数值跟参数牌列表的分数值不一样
        if(value - hand.value != 0)
        {
//            if (value==HUOJIAN) return 1;//如果我的牌是火箭则我的牌大
//            if (hand.value==HUOJIAN) return -1;//如果他的牌是火箭则他的牌大

//            if (value==BOMB) return 1;//如果我的牌是炸弹则我的牌大
//            if (hand.value==BOMB) return -1;//如果他的牌是炸弹则他的牌大
            if (value==BOMB && hand.value<BOMB) return 1;//如果我的牌是炸弹则我的牌大  //bug fix 2005.5.19
            if (hand.value==BOMB && value<BOMB) return -1;//如果他的牌是炸弹则他的牌大
            
            if (value==RUAN_BOMB && hand.value<RUAN_BOMB) return 1;
            if (hand.value==RUAN_BOMB && value<RUAN_BOMB) return -1;

            return -1;//由于我的牌的值不等于他的牌的值,由于我是后出牌的,则我的牌不能出出去
        }

        //程序执行到这里的时候我的牌值是等于他的牌值的!------------------------------
        if(size() != hand.size()) return 0;//如果本牌列表的个数根参数牌列表的个数不一样,则直接返回0,表示本牌列表不大于参数派列表

        //现在本牌列表的牌的个数等于参数牌列表的牌个数,则分别取出两者各自最大的牌
        Card card = bigCard();
        Card card1 = hand.bigCard();
        return card.compareDDzTo(card1); //比较各自最大的牌
    }


    /**
     * 对card排序
     */
    public static void sortCards(Vector<Card> aVec)
    {
        int k;
        Card a,b;

        //排序算法
        for (int i = 0; i < aVec.size() - 1; i++)
        {
            k = i;
            for (int j = i + 1; j < aVec.size(); j++)
            {
                a =  aVec.get(k);
                b =  aVec.get(j);
                if (a.compareTo(b) > 0)
                    k = j;
            }
            if (k != i)
            {
                a =  aVec.get(i);
                b =  aVec.get(k);
                aVec.setElementAt(b, i);
                aVec.setElementAt(a, k);
            }
        }
    }


    public Card bigCard()
    {
        return bigcard;
    }
    
    public Card smallCard() {
        return smallCard;
    }
    
}
